package com.libgdxbar.pvzlikegame.entities;

import com.badlogic.gdx.utils.Disposable;
import com.badlogic.gdx.utils.IntMap;

import java.util.LinkedHashMap;
import java.util.Map;

public final class GameWorld implements Disposable {

	// 使用Singleton模式确保只有一个GameWorld实例
	@SuppressWarnings("GDXJavaStaticResource")
	private static GameWorld instance;

	// 存储所有实体对象的映射
	private IntMap<Entity> entities = new IntMap<>();

	// 存储所有系统（负责处理特定实体逻辑）
	private Map<Class<?>, EntitySystem> systems = new LinkedHashMap<>();

	// 存储所有监听器（监听实体的添加与移除）
	private Map<Class<?>, EntityListener> listeners = new LinkedHashMap<>();

	/**
	 * 构造器私有化，确保外部无法直接创建GameWorld实例
	 */
	private GameWorld() {
		if (instance != null) {
			throw new RuntimeException("单例模式，GameWorld实例已存在");
		}
	}

	/**
	 * 获取GameWorld的单例实例
	 *
	 * @return GameWorld的实例
	 */
	public static synchronized GameWorld getInstance() {
		if (instance == null) {
			instance = new GameWorld();
		}
		return instance;
	}

	/**
	 * 向GameWorld中添加一个实体对象
	 *
	 * @param entity 要添加的实体对象
	 */
	public void addEntity(Entity entity) {
		// 防止重复添加实体
		if (entities.containsKey(entity.id)) {
			return;
		}
		// 通知监听器，实体已被添加
		for (EntityListener listener : listeners.values()) {
			listener.onEntityAdded(entity);
		}
		entities.put(entity.id, entity);
	}

	/**
	 * 从GameWorld中移除一个实体对象
	 *
	 * @param entity 要移除的实体对象
	 */
	public void removeEntity(Entity entity) {
		// 如果实体不存在
		if (!entities.containsKey(entity.id)) {
			return;
		}
		// 通知监听器，实体已被移除
		for (EntityListener listener : listeners.values()) {
			listener.onEntityRemoved(entity);
		}
		entities.remove(entity.id);
	}

	/**
	 * 获取某个实体系统
	 *
	 * @param clazz 实体系统的类类型
	 * @param <T>   实体系统的类型
	 * @return 实体系统的实例
	 */
	public <T extends EntitySystem> T getSystem(Class<T> clazz) {
		return (T) systems.get(clazz);
	}

	/**
	 * 向GameWorld中添加一个实体系统
	 *
	 * @param system 要添加的实体系统
	 */
	public void addSystem(EntitySystem system) {
		// 防止重复添加系统
		if (!systems.containsKey(system.getClass())) {
			systems.put(system.getClass(), system);
			// 添加系统时，自动将其作为实体监听器
			this.addEntityListener(system);
		}
	}

	/**
	 * 从GameWorld中移除一个实体系统
	 *
	 * @param clazz 要移除的实体系统的类类型
	 */
	public void removeSystem(Class<? extends EntitySystem> clazz) {
		EntitySystem systemToRemove = systems.remove(clazz);
		this.removeEntityListener(systemToRemove);
	}

	/**
	 * 向GameWorld中添加一个实体监听器
	 *
	 * @param listener 要添加的实体监听器
	 */
	public void addEntityListener(EntityListener listener) {
		listeners.put(listener.getClass(), listener);
	}

	/**
	 * 从GameWorld中移除一个实体监听器
	 *
	 * @param listener 要移除的实体监听器
	 */
	public void removeEntityListener(EntityListener listener) {
		listeners.remove(listener.getClass());
	}

	/**
	 * 更新所有系统中的实体
	 *
	 * @param delta 上次更新以来的时间间隔
	 */
	public void update(float delta) {
		for (EntitySystem system : systems.values()) {
			system.run(delta);
		}
	}

	/**
	 * 释放GameWorld所管理的所有资源
	 */
	@Override
	public void dispose() {
		// 释放所有监听器的资源
		for (EntityListener listener : listeners.values()) {
			if (listener instanceof Disposable) {
				Disposable disposable = (Disposable) listener;
				disposable.dispose();
			}
		}

		// 释放所有实体的资源
		for (Entity entity : entities.values()) {
			if (entity instanceof Disposable) {
				Disposable disposable = (Disposable) entity;
				disposable.dispose();
			}
		}

		// 清理所有数据
		entities.clear();
		listeners.clear();
		systems.clear();
	}

}
